#ifndef AVALON_ACCEPTSTATE_HPP
#define AVALON_ACCEPTSTATE_HPP
#include <boost/noncopyable.hpp>
#include "Avalon/IO/IO.hpp"
#include "Avalon/Threading/Async.hpp"

namespace Avalon {
namespace IO {

  /*! \class AcceptState
   *  \brief Manages the state of a ServerConnection's accept operation.
   *  \tparam ChannelType The type of Channel to accept.
   */
  template<typename ChannelType>
  class AcceptState : boost::noncopyable {
    public:

      //! Constructs an AcceptState.
      AcceptState();

      ~AcceptState();

      //! Initializes the AcceptState.
      /*!
        \param serverConnection The ServerConnection executing the accept.
        \param acceptSlot The slot to call when the accept operation completes.
      */
      void Initialize(ServerConnection* serverConnection, const typename
        Threading::Async<ChannelType*>::FinishedSlot& acceptSlot);

      //! Returns the Channel that was accepted.
      ChannelType* GetChannel() const;

      //! Returns the State of the accept operation.
      typename Threading::Async<IO::Channel*>::State GetState() const;

      //! Updates the State of the accept operation.
      void UpdateState();

      //! Starts the next accept operation.
      void Accept();

    private:
      IO::ServerConnection* m_serverConnection;
      Threading::Async<Channel*> m_acceptResult;
      typename Threading::Async<Channel*>::State m_acceptState;
  };

  template<typename ChannelType>
  AcceptState<ChannelType>::AcceptState() {}

  template<typename ChannelType>
  AcceptState<ChannelType>::~AcceptState() {
    assert(m_acceptState != Threading::Async<Channel*>::PENDING);
  }

  template<typename ChannelType>
  void AcceptState<ChannelType>::Initialize(ServerConnection* serverConnection,
      const typename Threading::Async<ChannelType*>::FinishedSlot& acceptSlot) {
    m_serverConnection = serverConnection;
    m_acceptResult.SetFinishedSlot(acceptSlot, Store(m_acceptState));
    assert(m_acceptState == Threading::Async<Channel*>::PENDING);
  }

  template<typename ChannelType>
  ChannelType* AcceptState<ChannelType>::GetChannel() const {
    return static_cast<ChannelType*>(m_acceptResult.Get());
  }

  template<typename ChannelType>
  typename Threading::Async<IO::Channel*>::State
      AcceptState<ChannelType>::GetState() const {
    return m_acceptState;
  }

  template<typename ChannelType>
  void AcceptState<ChannelType>::UpdateState() {
    m_acceptState = m_acceptResult.GetState();
  }

  template<typename ChannelType>
  void AcceptState<ChannelType>::Accept() {
    m_acceptResult.ResetResult();
    m_serverConnection->Accept(Store(m_acceptResult));
  }
}
}

#endif // AVALON_ACCEPTSTATE_HPP
